﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using RobotRace.engine.robossConnector;
using FIRADriverLibrary;
using RobotRace.engine.raceengine;
using RobotRace.engine.agents;
using RobotRace.engine.agents.implementation;
using System.Threading;
using RobotRace.Geometry;
using RobotRace.engine.path;
using RobotRaceGUI.AgentConfigurationForms;

namespace RobotRaceGUI
{
    public partial class MainUserForm : Form
    {
        private RobossConnector robossConnector;

        public MainUserForm(RobossConnector robossConnector)
        {
            InitializeComponent();
            this.robossConnector = robossConnector;
            InitializeRobotList();
            InitializePitch();
            Initialize2DAreaPaint();
        }

        [STAThread]
        static void Main()
        {
            ConnectForm connectForm = new ConnectForm();
            DialogResult result = connectForm.ShowDialog();
            if (result == DialogResult.OK)
            {
                Application.Run(new MainUserForm(connectForm.connector));
            }
        }

        private void configureRaceButton_Click(object sender, EventArgs e)
        {
            if (raceEngine != null)
            {
                if (!raceEngine.isStopped())
                {
                    raceEngine.stopRace();
                }
                robossConnector.releaseAllOwnedRobots();
            }
            //Agent agent = new PIDPointFollower(robotsStartingPoints[0], robossConnector.getRobots()[0], checkpoints);
            //Agent agent = new SimplePointFollower(robotsStartingPoints[0], robossConnector.getRobots()[0], checkpoints);
            List<Agent> configuredAgents = new List<Agent>();
            foreach (AgentForGUI guiAgent in agents){
                configuredAgents.Add(guiAgent.Agent);
            }
            raceEngine = new RaceEngine(configuredAgents, robossConnector);
            robossConnector.requestAllRobots();
            //raceEngine.startRace();
            startButton.Enabled = true;
            stopButton.Enabled = false;
            pauseButton.Enabled = false;
            resumeButton.Enabled = false;
            bestLapTimeLabel.Text = "--:--:--";
            raceEngine.resetBestLap();
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            if (raceEngine == null)
            {
                MessageBox.Show("Cannot start race if none was configured!");
                return;
            }
            raceEngine.startRace();
            stopButton.Enabled = true;
            pauseButton.Enabled = true;
            startButton.Enabled = false;
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            if (raceEngine == null)
            {
                MessageBox.Show("Cannot stop race if none was started!");
                return;
            }
            if (raceEngine.isStopped())
            {
                MessageBox.Show("Cannot stop race that was already stopped!");
                return;
            }
            raceEngine.stopRace();
            startButton.Enabled = true;
            pauseButton.Enabled = false;
            resumeButton.Enabled = false;
            stopButton.Enabled = false;
        }

        private void pauseButton_Click(object sender, EventArgs e)
        {
            if (raceEngine == null)
            {
                MessageBox.Show("Cannot pause race if none was started!");
                return;
            }
            if (raceEngine.isStopped())
            {
                MessageBox.Show("Cannot pause race that was already stopped!");
                return;
            }
            raceEngine.pauseRace();
            pauseButton.Enabled = false;
            resumeButton.Enabled = true;
        }

        private void resumeButton_Click(object sender, EventArgs e)
        {
            if (raceEngine == null)
            {
                MessageBox.Show("Cannot resume race if none was started!");
                return;
            }
            if (raceEngine.isStopped())
            {
                MessageBox.Show("Cannot resume race that was already stopped!");
                return;
            }
            raceEngine.resumeRace();
            pauseButton.Enabled = true;
            resumeButton.Enabled = false;
        }

        private void clearCheckpointsButton_Click(object sender, EventArgs e)
        {
            Monitor.Enter(checkpointsMutex);
            if (checkpoints == null){
                checkpoints = new List<Point2D>();
            }
            checkpoints.Clear();
            recomputePathsInAllAgents();
            Monitor.Exit(checkpointsMutex);
        }

        private void recomputePathsInAllAgents()
        {
            foreach (AgentForGUI agent in agents)
            {
                agent.Agent.recomputePath();
            }
        }

        private void optimizePathButton_Click(object sender, EventArgs e)
        {
            List<Point2D> newCheckpoints = PathOptimizer.optimize(checkpoints, pitch.getWalls(), 0.25, 0.1);
            Monitor.Enter(checkpointsMutex);
            checkpoints.Clear();
            checkpoints.AddRange(newCheckpoints);
            Monitor.Exit(checkpointsMutex);
            recomputePathsInAllAgents();
        }

        private void editTeamButton_Click(object sender, EventArgs e)
        {
            AgentForGUI selectedAgent = teamsList.SelectedItem as AgentForGUI;
            if (selectedAgent == null)
            {
                MessageBox.Show("Please select agent to edit first.");
                return;
            }
            selectedAgent.AgentConfigurationForm.Show();
        }

        private void deleteTeamButton_Click(object sender, EventArgs e)
        {
            AgentForGUI selectedAgent = teamsList.SelectedItem as AgentForGUI;
            if (selectedAgent == null)
            {
                MessageBox.Show("Please select agent to delete.");
                return;
            }
            if (agents.Remove(selectedAgent))
            {
                refreshTeamsList(agents);
                unassignedRobots.AddRange(selectedAgent.Agent.ControlledRobots);
                MessageBox.Show("Agent removed: " + selectedAgent.Name);
            }
            else
            {
                MessageBox.Show("Cold not remove agent: " + selectedAgent.Name + "!");
            }
            
        }

        private void addTeamButton_Click(object sender, EventArgs e)
        {
            NewTeamForm newTeamForm = new NewTeamForm(unassignedRobots, checkpoints);
            newTeamForm.ShowDialog();
            Agent agent = newTeamForm.NewAgent;
            if (!newTeamForm.CreateButtonClicked)
            {
                return;
            }
            if (agent == null)
            {
                MessageBox.Show("ERROR: New agent was not configured correctly!");
                return;
            }
            foreach (FIRARobotState robotControlledByAgent in agent.ControlledRobots){
                unassignedRobots.Remove(robotControlledByAgent);
            }
            Form configForm = newTeamForm.AgentConfigurationForm;
            AgentForGUI agentForGUI = new AgentForGUI();
            agentForGUI.Agent = agent;
            agentForGUI.AgentConfigurationForm = configForm;
            agents.Add(agentForGUI);
            refreshTeamsList(agents);

            MessageBox.Show("New agent has been added. Please configure the race once again in order to apply changes.");
        }


    }
}
